﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using AudioPlayer.GUI.Theme;
using System.Drawing.Drawing2D;
using AudioPlayer.GUI.Main;
using AudioPlayer.Plugin.Storage;

namespace AudioPlayer.GUI.Progress {
	/// <summary>
	/// Progress control.
	/// </summary>
	internal class ProgressControl : ProgressBar {
		#region Fields
		private bool _mouseDown;
		private Timer _timer;
		#endregion
		#region Constructor
		/// <summary>
		/// Initializes a new instance of the <see cref="ProgressControl"/> class.
		/// </summary>
		public ProgressControl() {
			this.Init();
		}
		#endregion
		#region Private Voids
		/// <summary>
		/// Inits this instance.
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		private void Init() {
			if (!this.DesignMode) {
				this.Height = 16;
				this.MaximumSize = new System.Drawing.Size(100, 16);
				this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);

				Config.Plugins.PlayControl.Starting += new EventHandler(PlayControl_Starting);
				Config.Plugins.PlayControl.Ending += new EventHandler(PlayControl_Ending);
			}
		}	
		private void TimerStart() {
			if (_timer == null) {
				_timer = new Timer();
			}
			_timer.Interval = 100;
			_timer.Tick += new EventHandler(Timer_Tick);
			_timer.Start();
		}
		private void TimerStop() {
			if (_timer != null) {
				_timer.Stop();
				_timer.Dispose();
				_timer = null;
			}
		}
		/// <summary>
		/// Draws the control
		/// </summary>
		/// <param name="g">The graphics.</param>
		private void Draw(Graphics g) {
			//Check if everything is ok.
			if (g != null && this.Created) {
				this.DrawBackground(g);
				this.DrawValue(g);
			}
		}
		/// <summary>
		/// Draws the background.
		/// </summary>
		/// <param name="g">The graphics.</param>
		private void DrawBackground(Graphics g) {
			LinearGradientBrush brushBg = new LinearGradientBrush(this.ClientRectangle, 
				ThemeManager.ActiveColorTable.ToolStripBackground1, 
				ThemeManager.ActiveColorTable.ToolStripBackground2, 
				LinearGradientMode.Vertical);
			g.FillRectangle(brushBg, this.ClientRectangle);
			//cleanup
			brushBg.Dispose();
		}

		/// <summary>
		/// Draws the progress value.
		/// </summary>
		/// <param name="g">The graphics.</param>
		private void DrawValue(Graphics g) {
			if (this.Value > 0) {
				float w = (this.Value * this.Width) / 100f;
				Rectangle rect = new Rectangle(0, 0, (int)w, this.Height);
				LinearGradientBrush brushBg = new LinearGradientBrush(rect,
					ThemeManager.ActiveColorTable.ProgressActiveBackground1,
					ThemeManager.ActiveColorTable.ProgressActiveBackground2,
					LinearGradientMode.Vertical);

				//Draw
				g.FillRectangle(brushBg, rect);

				//Clean
				brushBg.Dispose();
			}
		}

		private void DrawBuffer(Graphics g) {
			//Double buffer
			Bitmap bmp = new Bitmap(this.Width, this.Height);
			Graphics gBuffer = Graphics.FromImage(bmp);
			//Draw up
			this.Draw(gBuffer);
			g.DrawImage(bmp, new Point(0, 0));
			//Clean up
			bmp.Dispose();
			gBuffer.Dispose();
		}

		/// <summary>
		/// Seeks the specified percent.
		/// </summary>
		/// <param name="percent">The percent.</param>
		private void Seek(int percent) {
			Config.Plugins.PlayControl.Seek(percent, System.IO.SeekOrigin.Begin);
		}

		/// <summary>
		/// Resets the timer.
		/// </summary>
		private void Reset() {
			this.Value = 0;
			TimerStop();
			TimerStart();
		}
		#endregion
		#region Override
		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
		/// </summary>
		/// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
		protected override void OnPaint(PaintEventArgs e) {
			if (this.CustomDraw) {
				this.DrawBuffer(e.Graphics);
			} else {
				base.OnPaint(e);
			}
			base.OnPaint(e);
		}
		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.MouseDown"/> event.
		/// </summary>
		/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
		protected override void OnMouseDown(MouseEventArgs e) {
			if (Config.Plugins.PlayControl.IsPlaying) {
				int value = (int)(((float)e.X / (float)this.Width) * 100f);
				if (value > 0 && value < 100) {
					this.Value = value;
					this.Seek(value);
				} else {
					if (value > 100) {
						value = 100;
					} else {
						value = 0;
					}
				}
				_mouseDown = true;
			}
			base.OnMouseDown(e);
		}
		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.MouseMove"/> event.
		/// </summary>
		/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
		protected override void OnMouseMove(MouseEventArgs e) {
			if (_mouseDown && Config.Plugins.PlayControl.IsPlaying) {
				int value = (int)(((float)e.X / (float)this.Width) * 100f);

				if (value > 0 && value < 100) {
					this.Value = value;
					this.Seek(value);
				} else {
					if (value > 100) {
						value = 100;
					} else {
						value = 0;
					}
				}
			}
			base.OnMouseMove(e);
		}
		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.MouseLeave"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
		protected override void OnMouseLeave(EventArgs e) {
			_mouseDown = false;
			base.OnMouseLeave(e);
		}
		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"/> event.
		/// </summary>
		/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
		protected override void OnMouseUp(MouseEventArgs e) {
			_mouseDown = false;
			base.OnMouseUp(e);
		}
		#endregion
		#region Property
		/// <summary>
		/// Gets or sets a value indicating whether this control is custom draw.
		/// </summary>
		/// <value><c>true</c> if custom draw; otherwise, <c>false</c>.</value>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool CustomDraw {
			get {
				return Config.Settings.Cache.Get<bool>("ProgressControlCustomDraw", true);
			}
			set {
				Config.Settings.Cache.Set<bool>("ProgressControlCustomDraw", value);
			}
		}
		#endregion
		#region Event Handling
		/// <summary>
		/// Handles the Tick event of the Timer control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void Timer_Tick(object sender, EventArgs e) {
			if (Config.Plugins.PlayControl.IsPlaying) {
				double max = Config.Plugins.PlayControl.Duration;
				double cur = Config.Plugins.PlayControl.Current;

				if (cur > 0 && max > 0) {
					double value = (cur * 100) / max;
					int perc = (int)value;
					if (perc > 0 && perc < 100) {
						this.Value = perc;
						Graphics g = this.CreateGraphics();
						this.Draw(g);
						g.Dispose();
					}
				}
			} else {
				TimerStop();
			}
		}
		private void PlayControl_Ending(object sender, EventArgs e) {
			TimerStop();
		}
		private void PlayControl_Starting(object sender, EventArgs e) {
			this.Reset();
		}
		#endregion
	}
}
